package se.webbzon.boltzmann.editor;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;

import se.webbzon.boltzmann.battle.factory.property.DefaultBPFGroup;
import se.webbzon.boltzmann.editor.component.imagelist.ImageSetEntry;
import se.webbzon.boltzmann.editor.component.texturelist.TextureSetEntry;
import se.webbzon.boltzmann.editor.environment.EditorEnvironment;
import se.webbzon.boltzmann.editor.environment.EditorInflatorGroup;
import se.webbzon.boltzmann.editor.factory.propertyframe.*;
import se.webbzon.boltzmann.editor.factory.worldobject.*;
import se.webbzon.boltzmann.editor.mvc.EditorListener;
import se.webbzon.boltzmann.editor.mvc.EditorModel;
import se.webbzon.boltzmann.editor.view.EditorContainer;
import se.webbzon.boltzmann.editor.view.EditorMenuBar;
import se.webbzon.boltzmann.editor.view.JScrollableDesktopPane;
import se.webbzon.boltzmann.editor.view.WorldViewContainer;
import se.webbzon.boltzmann.factory.AbstractFactoryException;
import se.webbzon.boltzmann.font.FontLoaderMap;
import se.webbzon.boltzmann.game.character.AbstractCharacterTextureSet;
import se.webbzon.boltzmann.game.character.CharacterLoader;
import se.webbzon.boltzmann.imageset.ImageSetLoaderMap;
import se.webbzon.boltzmann.inflatorgroup.DefaultInflatorGroup;
import se.webbzon.boltzmann.loader.LoaderException;
import se.webbzon.boltzmann.loader.LoaderUtility;
import se.webbzon.boltzmann.resource.Resources;
import se.webbzon.boltzmann.textureset.TextureSetLoaderMap;
import se.webbzon.oschi01.resourceset.ResourceSet;
import se.webbzon.oschi01.textureset.Texture3D;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldcamera.SimpleWorldRenderer;
import se.webbzon.oschi01.worldobject.WorldObject;

public class Main {
	
	// The title of the editor
	private static final String title = "Boltzmann Editor";
	
	// The frame associated with this program
	private static final JFrame frame = new JFrame(title + " - Unsaved file");

	public static void main(String[] args) {
		
		SimpleWorldRenderer.instance().setPaused(true);
		
		/** Load the resources **/
		LoaderUtility loaderUtility = new LoaderUtility();
		TextureSetLoaderMap tslm = new TextureSetLoaderMap();
		ImageSetLoaderMap islm = new ImageSetLoaderMap();
		Map<String, AbstractCharacterTextureSet> characterMap = new HashMap<String, AbstractCharacterTextureSet>();
		CharacterLoader cl = new CharacterLoader(characterMap); 
		FontLoaderMap flm = new FontLoaderMap();
		loaderUtility.addLoader(tslm);
		loaderUtility.addLoader(islm);
		loaderUtility.addLoader(cl);
		loaderUtility.addLoader(flm);
		try {
			loaderUtility.loadFromXML(ClassLoader.getSystemResource("gfx/resources.xml"));
			loaderUtility.loadFromXML(ClassLoader.getSystemResource("fonts/resources.xml"));
		} catch (LoaderException e) {
			e.printStackTrace();
		}
		Resources.setTextureSetMap(tslm.getMap());
		Resources.setImageSetMap(islm.getMap());
		Resources.setFontMap(flm.getMap());
		
		/** Create battle property factory group. **/
		DefaultBPFGroup bpfGroup = null;
		try {
			bpfGroup = new DefaultBPFGroup();
		} catch (AbstractFactoryException e) {
			e.printStackTrace();
		}
		
		/** Create inflator group **/
		DefaultInflatorGroup big = new EditorInflatorGroup(bpfGroup);
		
		/** Create the environment **/
		EditorEnvironment env = null;
		try {
			env = new EditorEnvironment(big);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		/** Initialize desktop pane and model **/
		JDesktopPane jdp = new JScrollableDesktopPane();
		jdp.setPreferredSize(new Dimension(4000,4000));
		
		EditorModel model = new EditorModel(big,jdp);
		model.addListener(new EditorListenerImpl());
		
		/** Create sorted texture set **/
		TreeSet<TextureSetEntry> textures = new TreeSet<TextureSetEntry>();
		for (Entry<String,ResourceSet<Texture3D>> texture : tslm.getMap().entrySet())
			textures.add(new TextureSetEntry(texture));
		
		/** Create sorted image set **/
		TreeSet<ImageSetEntry> images = new TreeSet<ImageSetEntry>();
		for (Entry<String,ResourceSet<Image>> image : islm.getMap().entrySet())
			images.add(new ImageSetEntry(image));
		
		/** Create factories **/
		model.addWorldObjectFactory(new CubeFactory());
		model.addWorldObjectFactory(new ConeFactory());
		model.addWorldObjectFactory(new CylinderFactory());
		model.addWorldObjectFactory(new EllipsoidFactory());
		model.addWorldObjectFactory(new FloorFactory());
		model.addWorldObjectFactory(new WallFactory());
		model.addWorldObjectFactory(new XYPlaneFactory());
		model.addWorldObjectFactory(new XZPlaneFactory());
		model.addWorldObjectFactory(new YZPlaneFactory());
		model.addWorldObjectFactory(new DirectionalLightFactory());
		model.addWorldObjectFactory(new RoadPortalFactory(env));
		model.addWorldObjectFactory(new DoorPortalFactory(env));
		model.addWorldObjectFactory(new FactoryObjectFactory());
		model.addWorldObjectFactory(new BattleSpawnerFactory());
		model.addWorldObjectFactory(new HostileNPCSpawnerFactory());
		model.addWorldObjectFactory(new WaypointFactory(env));
		model.addWorldObjectFactory(new PlatformFactory());
		model.addWorldObjectFactory(new SequenceActionFactory(env));
		model.addWorldObjectFactory(new SequenceTriggerFactory(env));
		model.addWorldObjectFactory(new BackgroundFactory(env));
		model.addWorldObjectFactory(new FriendlyNPCSpawnerFactory());
		model.addWorldObjectFactory(new GameItemContainerFactory(env));
		model.addWorldObjectFactory(new PickupFactory(env));
		model.addWorldObjectFactory(new GameItemFactory(env));
		model.addWorldObjectFactory(new MathNoteFactory(env));
		model.addWorldObjectFactory(new SavePortalFactory(env));
		model.addWorldObjectFactory(new RestorationFactory());
		model.addWorldObjectFactory(new TargetFactory(env));
		model.addWorldObjectFactory(new FixedCameraFactory());
		model.addWorldObjectFactory(new SimplePortalFactory(env));
		model.addWorldObjectFactory(new ShopActionFactory(env));
		model.addWorldObjectFactory(new ShakeActionFactory(env));
		
		model.addPropertyFrameFactory(new GeometryPropertyFrameFactory(textures));
		model.addPropertyFrameFactory(new DirectionalLightPropertyFrameFactory());
		model.addPropertyFrameFactory(new RoadPortalPropertyFrameFactory());
		model.addPropertyFrameFactory(new DoorPortalPropertyFrameFactory(textures));
		model.addPropertyFrameFactory(new FactoryObjectPropertyFrameFactory());
		model.addPropertyFrameFactory(new BattleSpawnerPropertyFrameFactory());
		model.addPropertyFrameFactory(new HostileNPCSpawnerPropertyFrameFactory(bpfGroup,characterMap));
		model.addPropertyFrameFactory(new WaypointPropertyFrameFactory());
		model.addPropertyFrameFactory(new PlatformPropertyFrameFactory(textures));
		model.addPropertyFrameFactory(new PlatformShadowPropertyFrameFactory());
		model.addPropertyFrameFactory(new SequenceActionPropertyFrameFactory());
		model.addPropertyFrameFactory(new SequenceTriggerPropertyFrameFactory());
		model.addPropertyFrameFactory(new BackgroundPropertyFrameFactory(images));
		model.addPropertyFrameFactory(new FriendlyNPCSpawnerPropertyFrameFactory(characterMap));
		model.addPropertyFrameFactory(new GameItemContainerPropertyFrameFactory());
		model.addPropertyFrameFactory(new PickupPropertyFrameFactory());
		model.addPropertyFrameFactory(new GameItemPropertyFrameFactory());
		model.addPropertyFrameFactory(new MathNotePropertyFrameFactory());
		model.addPropertyFrameFactory(new SavePortalPropertyFrameFactory());
		model.addPropertyFrameFactory(new RestorationPropertyFrameFactory());
		model.addPropertyFrameFactory(new FixedCameraPropertyFrameFactory());
		model.addPropertyFrameFactory(new TargetPropertyFrameFactory());
		model.addPropertyFrameFactory(new SimplePortalPropertyFrameFactory());
		model.addPropertyFrameFactory(new ShopActionPropertyFrameFactory());
		model.addPropertyFrameFactory(new ShakeActionPropertyFrameFactory());
		
		// Create the containers
		WorldViewContainer worldViewContainer = new WorldViewContainer(model);
		EditorContainer editorContainer = new EditorContainer(model);
		EditorMenuBar editorMenuBar = new EditorMenuBar(worldViewContainer,model);
		
		// Initialize the main frame
		frame.add(new JScrollPane(jdp));
		frame.setJMenuBar(editorMenuBar);
		frame.setPreferredSize(new Dimension(1024,640));
		
		// Create the internal editor frame
		JInternalFrame internalFrame = new JInternalFrame("Editor",true,false,false);
		internalFrame.setLayout(new BorderLayout());
		internalFrame.add(worldViewContainer,BorderLayout.CENTER);
		internalFrame.add(editorContainer,BorderLayout.WEST);
		internalFrame.setPreferredSize(new Dimension(800,480));
		
		internalFrame.pack();
		internalFrame.setVisible(true);
		jdp.add(internalFrame);
		
		// Display the main frame
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		frame.pack();
		frame.setVisible(true);
	}
	
	public static final void exit() {
		System.exit(0);
	}
	
	private static final class EditorListenerImpl implements EditorListener {

		@Override public void onSelectFile(Object source, File file) {
			if (file == null)
				frame.setTitle(title + " - Unsaved file");
			else
				frame.setTitle(title + " - " + file.getAbsolutePath());
		}

		@Override public void onOpenWorld(Object source, WorldArea world) {};

		@Override public void onCloseWorld(Object source, WorldArea world) {};

		@Override public void onAddInstance(Object source, WorldObject instance) {};

		@Override public void onRemoveInstance(Object source, WorldObject instance) {};
		
		@Override public void onClearInstances(Object source) {};

		@Override public void onSelectInstances(
				Object source, 
				Collection<WorldObject> selectedInstances,
				Collection<WorldObject> deselectedInstances) {}

		@Override public void onChangeInstance(Object source, WorldObject instance) {};
		
		@Override public void onFocusInstance(Object source, WorldObject instance) {}
		
	}
	
}
